﻿using Qing.Lang;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Proto {
    /*对原生日期时间类型的封装*/
    public class DateObj : Obj {

        /************ 此处测试通过注解绑定对象成员 ****************/
/*        [BindAnno("#其他", "Second", typeof(DateTime))]
        public new object Raw { get; set; }

        [BindAnno("#备注")]
        public string remark;*/

        public DateObj() : base() {
            this.Raw = DateTime.Now;
            this.init();
        }

        public DateObj(DateTime dt) : base() {
            this.Raw = dt;
            this.init();
        }

        public override string toStr(string tp = "") {
            string dt = ((DateTime)Raw).ToString() ?? "";
            return "#(" + dt + ")" + base.toStr("");
        }


        public void init() {

            Map["#年份"] = new Expr(TP.Prop, new BindYear(this)); 
            Map["#月份"] = new Expr(TP.Prop, new BindMonth(this));
            Map["#日期"] = new Expr(TP.Prop, new BindDate(this));
            Map["#小时"] = new Expr(TP.Prop, new BindHour(this));
            Map["#分"] = new Expr(TP.Prop, new BindMinute(this));
            Map["#秒"] = new Expr(TP.Prop, new BindSecond(this));
            Map["#毫秒"] = new Expr(TP.Prop, new BindMillisecond(this));


            //Map["@格式化"] = new Expr(new DateFormat());   // 下方改为使用注解的方式声明
            Map["@取年份"] = new Expr(new DateGetYear());
            Map["@取月份"] = new Expr(new DateGetMonth());
            Map["@取日期"] = new Expr(new DateGetDay());
            Map["@取周几"] = new Expr(new DateGetDayOfWeek());
            Map["@取年内日数"] = new Expr(new DateGetDayOfYear());
            Map["@取小时"] = new Expr(new DateGetHours());
            Map["@取分钟"] = new Expr(new DateGetMinutes());
            Map["@取秒数"] = new Expr(new DateGetSecond());
            Map["@取毫秒"] = new Expr(new DateGetMill());
            Map["@取时钟"] = new Expr(new DateGetTicks());
            Map["@设年份"] = new Expr(new DateSetYear());
            Map["@设月份"] = new Expr(new DateSetMonth());
            Map["@设日期"] = new Expr(new DateSetDay());
            Map["@设小时"] = new Expr(new DateSetHours());
            Map["@设分钟"] = new Expr(new DateSetMinutes());
            Map["@设秒数"] = new Expr(new DateSetSecond());
            Map["@设毫秒"] = new Expr(new DateSetMill());

        }


        /*
         * ********************************    属性绑定方式    **********************************
         */

        //[BindAnno("#年份")]    //使用注解的方式绑定
        class BindYear : Prop {
            public BindYear(Obj obj) : base(obj) {}

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Year);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if(val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = val.Int().ToString() + "-";
                    dtStr += dt.ToString("MM-dd hh:mm:ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中年份必须为整数");
                }
            }
        }


        class BindMonth : Prop {
            public BindMonth(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Month);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-");
                    dtStr += val.Int().ToString();
                    dtStr += dt.ToString("-dd hh:mm:ss.fff");
                    obj.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中月份必须为整数");
                }
            }
        }

        class BindDate : Prop {
            public BindDate(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Date);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-");
                    dtStr += val.Int().ToString() + " ";
                    dtStr += dt.ToString("hh:mm:ss.fff");
                    obj.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中日期必须为整数");
                }
            }
        }

        class BindHour : Prop {
            public BindHour(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Hour);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd");
                    dtStr += " " + val.Int().ToString();
                    dtStr += dt.ToString(":mm:ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中小时必须为整数");
                }
            }
        }


        class BindMinute : Prop {
            public BindMinute(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Minute);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:");
                    dtStr += val.Int().ToString() + ":";
                    dtStr += dt.ToString("ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中分钟必须为整数");
                }
            }
        }

        class BindSecond : Prop {
            public BindSecond(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Second);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:mm:");
                    dtStr += val.Int().ToString() + ".";
                    dtStr += dt.ToString("fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中秒必须为整数");
                }
            }
        }

        class BindMillisecond : Prop {
            public BindMillisecond(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx=null) {
                return new Expr(TP.Int, ((DateTime)obj.Raw).Millisecond);
            }
            public override Expr Qset(Expr val, Ctx? ctx=null) {
                if (val.Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:mm:ss");
                    dtStr += "." + val.Int().ToString().PadLeft(3, '0');
                    obj!.Raw = DateTime.Parse(dtStr);
                    return val;
                } else {
                    return Expr.Err("日期时间类型中毫秒必须为整数");
                }
            }
        }



        /*
         * ********************************    方法绑定方式    **********************************
         */


        [BindAnno("@格式化")]
        class DateFormat : Native {
            public override string Name { get; set; } = "格式化";
            public override string Desc { get; set; } = "参数1-字符串，返回字符串，根据传入的格式字符串，将时间转换为字符串";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Str) {
                    return new Expr(TP.Str, ((DateTime)obj!.Raw).ToString(args[0].Str()));
                }


                return Expr.Err("时间类型·格式化方法参数错误");
            }

        }



        class DateGetYear : Native {
            public override string Name { get; set; } = "取年份";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的年份";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {


                return new Expr(TP.Int, ((DateTime)obj!.Raw).Year);


                return Expr.Err("时间类型·取年份方法参数错误");
            }

        }

        class DateGetMonth : Native {
            public override string Name { get; set; } = "取月份";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的月份";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Month + 1);

            }

        }

        class DateGetDay : Native {
            public override string Name { get; set; } = "取日期";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的日期";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Day + 1);
            }

        }

        class DateGetDayOfWeek : Native {
            public override string Name { get; set; } = "取周几";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的周几";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).DayOfWeek + 1);
            }

        }

        class DateGetDayOfYear : Native {
            public override string Name { get; set; } = "取年内日数";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的年内日数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).DayOfYear + 1);
            }

        }

        class DateGetHours : Native {
            public override string Name { get; set; } = "取小时";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的小时数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Hour);
            }

        }

        class DateGetMinutes : Native {
            public override string Name { get; set; } = "取分钟";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的分钟数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Minute);
            }

        }

        class DateGetSecond : Native {
            public override string Name { get; set; } = "取秒数";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的秒数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Second);
            }

        }

        class DateGetMill : Native {
            public override string Name { get; set; } = "取毫秒";
            public override string Desc { get; set; } = "无参，返回整数，获取时间对象的毫秒数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                return new Expr(TP.Int, ((DateTime)obj!.Raw).Millisecond);
            }

        }

        class DateGetTicks : Native {
            public override string Name { get; set; } = "取时钟";
            public override string Desc { get; set; } = "无参，返回字符串，获取时间对象的时钟";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {


                return new Expr(TP.Str, ((DateTime)obj!.Raw).Ticks.ToString());

            }

        }


        class DateSetYear : Native {
            public override string Name { get; set; } = "设年份";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的年份";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = args[0].Int().ToString() + "-";
                    dtStr += dt.ToString("MM-dd hh:mm:ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return new Expr(TP.Obj, obj);
                }

                return Expr.Err("时间类型·取时钟方法参数错误");
            }

        }

        class DateSetMonth : Native {
            public override string Name { get; set; } = "设月份";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的月份";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-");
                    dtStr += args[0].Int().ToString();
                    dtStr += dt.ToString("-dd hh:mm:ss.fff");
                    obj.Raw = DateTime.Parse(dtStr);
                    return new Expr(TP.Obj, obj);
                }

                return Expr.Err("时间类型·设月份方法参数错误");
            }

        }


        class DateSetDay : Native {
            public override string Name { get; set; } = "设日期";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的日期";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 1 && args[1].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-");
                    dtStr += args[1].Int().ToString() + " ";
                    dtStr += dt.ToString("hh:mm:ss.fff");
                    args[0].Val = DateTime.Parse(dtStr);
                    return args[0];
                }

                return Expr.Err("时间类型·设日期方法参数错误");
            }

        }

        class DateSetHours : Native {
            public override string Name { get; set; } = "设小时";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的小时";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd");
                    dtStr += " " + args[0].Int().ToString();
                    dtStr += dt.ToString(":mm:ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return new Expr(TP.Obj, obj);
                }

                return Expr.Err("时间类型·设小时方法参数错误");
            }

        }

        class DateSetMinutes : Native {
            public override string Name { get; set; } = "设分钟";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的分钟";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:");
                    dtStr += args[0].Int().ToString() + ":";
                    dtStr += dt.ToString("ss.fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return new Expr(TP.Obj, obj);
                }

                return Expr.Err("时间类型·设分钟方法参数错误");
            }

        }


        class DateSetSecond : Native {
            public override string Name { get; set; } = "设秒数";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的秒数";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:mm:");
                    dtStr += args[0].Int().ToString() + ".";
                    dtStr += dt.ToString("fff");
                    obj!.Raw = DateTime.Parse(dtStr);
                    return args[0];
                }

                return Expr.Err("时间类型·设秒数方法参数错误");
            }

        }

        class DateSetMill : Native {
            public override string Name { get; set; } = "设毫秒";
            public override string Desc { get; set; } = "参数1-整数，返回对象，设置时间对象的毫秒";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {

                if (args.Count > 0 && args[0].Tp == TP.Int) {
                    DateTime dt = ((DateTime)obj!.Raw);
                    string dtStr = dt.ToString("yyyy-MM-dd hh:mm:ss");
                    dtStr += "." + args[0].Int().ToString().PadLeft(3, '0');
                    obj!.Raw = DateTime.Parse(dtStr);
                    return new Expr(TP.Obj, obj);
                }

                return Expr.Err("时间类型·设毫秒方法参数错误");
            }

        }




    }


}

